/** ****************************************************************************
@addtogroup CascadeBus
@{
*******************************************************************************/

#include "stdinc.h"
#include "bsp.h"
#include "i2c.hpp"


void CI2cBus::init(ByteBuffer* prxb, I2C_TypeDef* i2cPort, u32 i2cSpeed, u8 i2cHardwareAddr)
{
    _i2cPort = i2cPort;
	_i2cHardwareAddr = i2cHardwareAddr;
	_prxb = prxb;
	_rxproto = NULL;

	/* _i2cPort DeInit */
	I2C_DeInit(_i2cPort);

	/*!< I2C configuration */
	/* sEE_I2C Peripheral Enable */
	I2C_Cmd(_i2cPort, ENABLE);
	/* _i2cPort configuration after enabling it */
	I2C_Init(_i2cPort, i2cSpeed, _i2cHardwareAddr, I2C_Mode_I2C, I2C_DutyCycle_2, \
			 I2C_Ack_Enable, I2C_AcknowledgedAddress_7bit);

	/* 使能 PEC calculation*/
	I2C_CalculatePEC(_i2cPort, ENABLE);
	I2C_TransmitPEC(_i2cPort, ENABLE);
}

int CI2cBus::send(u8 i2cHardwareAddr, void* _data, u16 len) {
	u32 time;
	int i = 0;
    u8* data = (u8*)_data;

	// While the bus is busy
	time = 1000;
	osDelayUsWhile(time, I2C_GetFlagStatus(_i2cPort, I2C_FLAG_BUSY));
	if(time == 0) {
		return 0;
	}

	// Disable Interrupt
	I2C_ITConfig(_i2cPort, (I2C_IT_TypeDef)(I2C_IT_ERR | I2C_IT_EVT | I2C_IT_BUF), DISABLE);

	do {
		// Send START condition
		I2C_GenerateSTART(_i2cPort, ENABLE);
		time = 500;
		osDelayUsUntil(time, I2C_CheckEvent(_i2cPort, I2C_EVENT_MASTER_MODE_SELECT));
		if(time == 0) break;

		// Send address for write
		I2C_Send7bitAddress(_i2cPort, i2cHardwareAddr, I2C_Direction_Transmitter);
		time = 500;
		osDelayUsUntil(time, I2C_CheckEvent(_i2cPort, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
		if(time == 0) break;

		for(i=0; i<len; i++) {
			// Send the byte to be written
			I2C_SendData(_i2cPort, data[i]);
			time = 500;
			osDelayUsUntil(time, I2C_CheckEvent(_i2cPort, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
			if(time == 0) break;
		}

		// PEC transfer
		// Send the byte to be written
		I2C_SendData(_i2cPort, I2C_GetPEC(_i2cPort));
		time = 500;
		osDelayUsUntil(time, I2C_CheckEvent(_i2cPort, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
		if(time == 0) break;
	} while(0);

	// 发送完成
	// Send STOP condition
    I2C_GenerateSTOP(_i2cPort, ENABLE);
	// Enable Interrupt
	I2C_ITConfig(_i2cPort, (I2C_IT_TypeDef)(I2C_IT_ERR | I2C_IT_EVT | I2C_IT_BUF), ENABLE);
	return i;
}

void CI2cBus::enableIrq(bool sw) {
    if(sw) {
        I2C_ITConfig(_i2cPort, (I2C_IT_TypeDef)(I2C_IT_ERR | I2C_IT_EVT | I2C_IT_BUF), ENABLE);
        //ITC_SetSoftwarePriority(i2cIRQn, ITC_PriorityLevel_2);
    } else {
        I2C_ITConfig(_i2cPort, (I2C_IT_TypeDef)(I2C_IT_ERR | I2C_IT_EVT | I2C_IT_BUF), DISABLE);
    }
}

/**
  * @brief  Checks whether the specified I2C interrupt has occurred or not.
  * @param  I2Cx: where x can be 1 to select the specified I2C peripheral.
  * @param  I2C_IT: specifies the interrupt source to check.
  *            This parameter can be one of the following values:
  *            @arg I2C_IT_SMBALERT: SMBus Alert interrupt
  *            @arg I2C_IT_TIMEOUT: Timeout or Tlow error interrupt
  *            @arg I2C_IT_PECERR: PEC error in reception  interrupt
  *            @arg I2C_IT_WUFH: Wakeup from Halt
  *            @arg I2C_IT_OVR: Overrun/Underrun flag (Slave mode)
  *            @arg I2C_IT_AF: Acknowledge failure flag
  *            @arg I2C_IT_ARLO: Arbitration lost flag (Master mode)
  *            @arg I2C_IT_BERR: Bus error flag
  *            @arg I2C_IT_TXE: Data register empty flag (Transmitter)
  *            @arg I2C_IT_RXNE: Data register not empty (Receiver) flag
  *            @arg I2C_IT_STOPF: Stop detection flag (Slave mode)
  *            @arg I2C_IT_ADD10: 10-bit header sent flag (Master mode)
  *            @arg I2C_IT_BTF: Byte transfer finished flag
  *            @arg I2C_IT_ADDR: Address sent flag (Master mode) ԁDSLԍ
  *                              Address matched flag (Slave mode)ԅNDADԍ
  *            @arg I2C_IT_SB: Start bit flag (Master mode)
  * @retval The new state of I2C_IT
  */

/**
  * @brief  Clear IT pending bit
  * @param  I2Cx: where x can be 1 to select the specified I2C peripheral.
  * @param  I2C_IT: specifies the interrupt pending bit to clear.
  *            This parameter can be any combination of the following values:
  *            @arg I2C_IT_SMBALERT: SMBus Alert interrupt
  *            @arg I2C_IT_TIMEOUT: Timeout or Tlow error interrupt
  *            @arg I2C_IT_PECERR: PEC error in reception  interrupt
  *            @arg I2C_IT_WUFH: Wakeup from Halt
  *            @arg I2C_IT_OVR: Overrun/Underrun interrupt (Slave mode)
  *            @arg I2C_IT_AF: Acknowledge failure interrupt
  *            @arg I2C_IT_ARLO: Arbitration lost interrupt (Master mode)
  *            @arg I2C_IT_BERR: Bus error interrupt
  *
  * @note   STOPF (STOP detection) is cleared by software sequence: a read operation
  *         to I2C_SR1 register (I2C_GetITStatus()) followed by a write operation to
  *         I2C_CR2 register (I2C_AcknowledgeConfig() to configure the I2C peripheral Acknowledge).
  * @note   ADD10 (10-bit header sent) is cleared by software sequence: a read
  *         operation to I2C_SR1 (I2C_GetITStatus()) followed by writing the second
  *         byte of the address in I2C_DR register.
  * @note   BTF (Byte Transfer Finished) is cleared by software sequence: a read
  *         operation to I2C_SR1 register (I2C_GetITStatus()) followed by a read/write to
  *         I2C_DR register (I2C_SendData()).
  * @note   ADDR (Address sent) is cleared by software sequence: a read operation
  *         to I2C_SR1 register (I2C_GetITStatus()) followed by a read operation
  *         to I2C_SR3 register ((void)(I2Cx->SR3)).
  * @note   SB (Start Bit) is cleared by software sequence: a read operation to
  *         I2C_SR1 register (I2C_GetITStatus()) followed by a write operation to
  *         I2C_DR register (I2C_SendData()).
  * @retval None
  */
void CI2cBus::irqHandler() {
    static I2C_Event_TypeDef event;
	static u8 ch;

    /*if( I2C_GetITStatus(_i2cPort, I2C_IT_SMBALERT) ) {
        I2C_ClearITPendingBit(_i2cPort, I2C_IT_SMBALERT);
        return;
    }
    if( I2C_GetITStatus(_i2cPort, I2C_IT_TIMEOUT) ) {
        I2C_ClearITPendingBit(_i2cPort, I2C_IT_TIMEOUT);
        return;
    }
    if( I2C_GetITStatus(_i2cPort, I2C_IT_PECERR) ) {
        I2C_ClearITPendingBit(_i2cPort, I2C_IT_PECERR);
        return;
    }
    if( I2C_GetITStatus(_i2cPort, I2C_IT_WUFH) ) {
        I2C_ClearITPendingBit(_i2cPort, I2C_IT_WUFH);
        return;
    }
    if( I2C_GetITStatus(_i2cPort, I2C_IT_OVR) ) {
        I2C_ClearITPendingBit(_i2cPort, I2C_IT_OVR);
        return;
    }
    if( I2C_GetITStatus(_i2cPort, I2C_IT_AF) ) {
        I2C_ClearITPendingBit(_i2cPort, I2C_IT_AF);
        return;
    }
    if( I2C_GetITStatus(_i2cPort, I2C_IT_ARLO) ) {
        I2C_ClearITPendingBit(_i2cPort, I2C_IT_ARLO);
        return;
    }
    if( I2C_GetITStatus(_i2cPort, I2C_IT_BERR) ) {
        I2C_ClearITPendingBit(_i2cPort, I2C_IT_BERR);
        return;
    }*/

	// Read SR2 register to get I2C errors
	if (I2C_ReadRegister(_i2cPort, I2C_Register_SR2)) {
		// Clears SR2 register
		_i2cPort->SR2 = 0;
        // 遇到以上错误就不能再继续往下处理了！
        return;
	}

    // 根据 I2C 接口事件类型进行不同处理
    event = I2C_GetLastEvent(_i2cPort);

    if(event == I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED) {
		// check on EV1
        // 清空缓冲区，准备接收数据
        _prxb->clear();
    }
    else if(event == I2C_EVENT_SLAVE_BYTE_RECEIVED) {
		// Check on EV2
        ch = I2C_ReceiveData(_i2cPort);
        if(!_prxb->putc(ch)) {
            // 数据缓冲区满，清空它
            _prxb->clear();
        }
    }
    else if(event == I2C_EVENT_SLAVE_STOP_DETECTED) {
		// Check on EV4
        // write to CR2 to clear STOPF flag
        I2C1->CR2 |= I2C_CR2_ACK;

        // 检验 PEC 校验和(==0 表示 OK)
        if(I2C_GetPEC(_i2cPort) == 0) {
            if(!_rxproto) {
                // 未提供协议处理器，丢弃
            } else {
                // 数据校验正确，交给协议层处理
                // _prxb->len()-1 是因为最后一个字节是 PEC，验证完成后就可以不要了！
                _rxproto->onRxPacket(this, _prxb->getbs(), _prxb->len());
            }
        }
        _prxb->clear();
	}
    else {
		/* Cleared by software reading SR1 followed by either a read
		 or write in the DR register or by hardware after a start
		 or a stop condition in transmission or when PE=0.
		*/
        // 清除BTF位
		_i2cPort->SR1;
		I2C_ReceiveData(_i2cPort);

		/*
		Cleared by software reading or writing the DR register or by hardware when PE=0.
		Note: RXE cannot be cleared by reading a data when the BTF bit is set as the DR register is still full
			  in this case.
		*/
		// 清除 RXNE 位
		_i2cPort->SR1;
		I2C_ReceiveData(_i2cPort);
		_i2cPort->SR3 = 0;
        _prxb->clear();
	}
}
